/**
* @program: src
*
* @description:
*
* @author: Mr.chen
*
* @create: 2020-12-18 17:06
**/
package handle

import (
	"ydd-im/service/api/define"
	"ydd-im/service/api/tools/balance"
	"ydd-im/service/dbproxy/proto"
	"ydd-im/util/logger"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/afex/hystrix-go/hystrix"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"strconv"
	"strings"
)
/**
 * 连接grpc
 * @access  public
 * @return  string addr ip+port
 * @return  error err
 */
func grpcConnPlus(addr string) (conn *grpc.ClientConn,err error) {
	fmt.Println(addr)
	conn, err = grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		logger.GetLg().Error("did not connect",
			zap.Any("err",err),
		)
		return nil,err
	}
	return conn,nil
}

/**
 * 获取grpc地址,包含其它
 * @access  public
 * @return  string addr ip+port
 * @return  error err
 */
func GetBalanceAddrPlus() (addr string,err error) {
	if len(define.DbproxyServerList) ==0 {
		return "",errors.New("数据库服务器不可用")
	}
	var insts []*balance.Instance
	for k,_ :=range define.DbproxyServerList {
		ServerListAddr := strings.Split(define.DbproxyServerList[k],":")
		port,_ :=strconv.Atoi(ServerListAddr[1])
		one := balance.NewInstance(ServerListAddr[0],port)
		insts = append(insts, one)
	}
	if len(insts)==0 {
		logger.GetLg().Info("服务不存在",
			zap.String("host",define.LocalHost),
			zap.String("port",define.Port),
			zap.Any("err",errors.New("远程地址不能为空")),
		)
		return "",errors.New("远程地址不能为空")
	}
	var balanceName = "roundrobin"
	inst, err := balance.DoBalance(balanceName, insts)
	if err != nil {
		return "",err
	}
	addr = fmt.Sprintf("%s:%d",inst.GetHost(),inst.GetPort())
	return addr,nil
}



/**
 *rpc调用函数封装execAction : 向dbproxy请求执行action
 * @access  public
 * @param   string     funcName  函数名
 * @param   string     paramJson  参数
 * @return *pb.RespExec data 返回结果
 * @return  error err
 */
func execAction(funcName string, paramJson []byte,servername string,iscontain bool) (data *proto.RespDbExec,err  error) {
	addr,err := GetBalanceAddrPlus()
	if err != nil {
		return nil,err
	}
	fmt.Println("服务器地址",addr)
	conn,err := grpcConnPlus(addr)
	defer conn.Close()
	if err != nil {
		return nil,err
	}
	hystrix.ConfigureCommand("Login", hystrix.CommandConfig{
		Timeout:               1000,
		MaxConcurrentRequests: 100,
		RequestVolumeThreshold:50,
		ErrorPercentThreshold: 25,
	})
	dataChan := make(chan *proto.RespDbExec, 1)
	err = hystrix.Do("Login", func() error {
		dbCli :=  proto.NewDBProxyDbServiceClient(conn)
		resp,err := dbCli.ExecuteDbAction(context.TODO(), &proto.ReqDbExec{
			Action: []*proto.SingleDbAction{
				&proto.SingleDbAction{
					Name:   funcName,
					Params: paramJson,
				},
			},
		})

		if err != nil  {
			return err
		}
		dataChan<-resp
		return nil
	}, nil) // fallback没有处理错误请置为空，否则会处理错误
	if err !=nil {
		logger.GetLg().Error("failed to call",
			zap.Any("err",err),
		)
		return data,err
	}
	if list, ok := <-dataChan;ok {
		close(dataChan)
		return list,nil
	}
	close(dataChan)
	return data,nil

}

// parseBody : 转换rpc返回的结果
func parseBody(resp *proto.RespDbExec) *define.ExecResult {
	if resp == nil || resp.Data == nil {
		return nil
	}
	resList := []define.ExecResult{}
	_ = json.Unmarshal(resp.Data, &resList)
	// TODO:
	if len(resList) > 0 {
		return &resList[0]
	}
	return nil
}
